<HTML><title>Performance Notes</title>
<BODY>
<h1>Matrix Performance Notes</h1>
<p>While the matrix interface is always identical, performance characteristics 
  are implementation dependent. In general, performance of a matrix operation 
  is a function of <i>{data structure, density, type and kind of method arguments}</i>. 
  This library takes great care about performance. When in doubt about the detailed 
  character of an operation, have a look at the source code. </p>
<p>In practice, sparse matrices are used for one of two reasons: To safe memory 
  or to speed up computation. Hash based sparse matrices (<a href="../impl/SparseDoubleMatrix2D.html">SparseDoubleMatrix2D</a>) 
  are neither the smallest possible matrix representation nor the fastest. They 
  implement a reasonable trade-off between performance and memory: Very good average 
  performance on get/set operations at quite small memory footprint. They are 
  also suited for special-purpose algorithms exploiting explicit knowledge about 
  what regions are zero and non-zero, but not quite as good as other sparse matrix 
  representations. For example, sparse linear algebraic matrix multiplies, inversions, 
  etc. better work on sparse row compressed (<a href="../impl/RCDoubleMatrix2D.html">RCDoubleMatrix2D</a>). 
  However, alternative sparse matrix representations are really only usable for 
  special purposes, because their get/set performance can be very bad. In contrast, 
  hash based sparse matrices are more generally applicable data structures. </p>
<p> Here is a list describing which combinations are particularly optimized. (<tt>F</tt> 
  is used as shortcut for <samp>cern.jet.math.Functions</samp>)</p>
<h3>General Remarks</h3>
Matrix-matrix and matrix-vector multiplication <tt>C = alpha*AxB + beta*C</tt> 
: 
<blockquote> 
  <p>For good performance B,C may have any type. For A={SparseDoubleMatrix2D,RCDoubleMatrix2D} 
    this is only fast if the density of A is small. For A={DenseDoubleMatrix2D} 
    density does not matter. If A is dense and B is sparse, this is no problem, 
    because even then the quick sparse mult is used.</p>
</blockquote>
<h3>DenseDoubleMatrix2D</h3>
<p></p>
<p></p>
<i>Dense row major format</i>. Essentially all methods highly optimized. This 
is almost always the implementation type to go for. It is also most easily to 
understand. The types below are only useful for very specific use cases. 
<h3>RCDoubleMatrix2D</h3>
<p></p>
<p></p>
<i>Sparse row-compressed format</i>. Special-purpose implementation. Thus some 
operations very efficient, others quite slow. Essentially designed to support 
the fastest possible sparse matrix-matrix and matrix-vector multiplications as 
well as sparse linear algebra. Efficient methods are: 
<table width="100%" border="1" cellspacing="0">
  <tr bgcolor="#339933"> 
    <td width="19%">Operation</td>
    <td width="35%">Method</td>
    <td width="46%">Comment</td>
  </tr>
  <tr> 
    <td width="19%">read</td>
    <td width="35%">get,getQuick</td>
    <td width="46%">always</td>
  </tr>
  <tr> 
    <td width="19%">write</td>
    <td width="35%">set,setQuick</td>
    <td width="46%"> 
      <p>only fast if the matrix is really sparse and in a loop iterating upwards:<br>
        <tt>for (int i=0; i&lt;rows; i++) { for (int j=0; j&lt;columns; j++) { 
        setQuick(i,j,...) ... }}</tt></p>
    </td>
  </tr>
  <tr> 
    <td width="19%">matrix-matrix and matrix-vector multiplication</td>
    <td width="35%">zMult</td>
    <td width="46%">see above in Section &quot;General&quot;</td>
  </tr>
  <tr> 
    <td width="19%">elementwise scaling</td>
    <td width="35%">assign(f) where f is one of {F.mult(a),F.div(a)}</td>
    <td width="46%"><tt>x[i,j] = x[i,j] {*,/} a</tt></td>
  </tr>
  <tr> 
    <td width="19%">elementwise scaling</td>
    <td width="35%">assign(y,f) where f is one of {F.plus,F.minus, F.mult,F.div, 
      F.plusMult(a),F.minusMult(a)}</td>
    <td width="46%"><tt>x[i,j] = x[i,j] {+,-,*,/} y[i,j]<br>
      x[i,j] = x[i,j] {+,-} y[i,j] {*,/} a</tt></td>
  </tr>
  <tr> 
    <td width="19%">copying</td>
    <td width="35%">assign(othermatrix)</td>
    <td width="46%">always fast, best if othermatrix is a RCDoubleMatrix2D</td>
  </tr>
  <tr> 
    <td width="19%">iteration</td>
    <td width="35%">forEachNonzero(function)</td>
    <td width="46%">most of the time the preferred way for iteration and modification</td>
  </tr>
  <tr> 
    <td width="19%">&nbsp;</td>
    <td width="35%">&nbsp;</td>
    <td width="46%">&nbsp;</td>
  </tr>
</table>
<table width="75%" border="1">
</table>
<h3>SparseDoubleMatrix2D</h3>
<p></p>
<p></p>
<i>Sparse hash format</i>. General-purpose sparse implementation. Designed for 
efficient random access to sparse structures. Thus, performance more balanced 
than RCDoubleMatrix2D. Never really slow, often faster than RCDoubleMatrix2D, 
sometimes slightly slower. Efficient methods are: 
<table width="100%" border="1" cellspacing="0">
  <tr bgcolor="#339933"> 
    <td width="20%">Operation</td>
    <td width="35%">Method</td>
    <td width="45%">Comment</td>
  </tr>
  <tr> 
    <td width="20%">read</td>
    <td width="35%">get,getQuick</td>
    <td width="45%">always</td>
  </tr>
  <tr> 
    <td width="20%">write</td>
    <td width="35%">set,setQuick</td>
    <td width="45%"> 
      <p>always</p>
    </td>
  </tr>
  <tr> 
    <td width="20%">matrix-matrix and matrix-vector multiplication</td>
    <td width="35%">zMult</td>
    <td width="45%">slightly slower than RCDoubleMatrix when size is large</td>
  </tr>
  <tr> 
    <td width="20%">elementwise scaling</td>
    <td width="35%">assign(f) where f is one of {F.mult(a),F.div(a)}</td>
    <td width="45%"><tt>x[i,j] = x[i,j] {*,/} a</tt></td>
  </tr>
  <tr> 
    <td width="20%">elementwise scaling</td>
    <td width="35%">assign(y,f) where f is one of {F.plus,F.minus, F.mult,F.div, 
      F.plusMult(a),F.minusMult(a)}</td>
    <td width="45%"><tt>x[i,j] = x[i,j] {+,-,*,/} y[i,j]<br>
      x[i,j] = x[i,j] {+,-} y[i,j] {*,/} a</tt></td>
  </tr>
  <tr> 
    <td width="20%">copying</td>
    <td width="35%">assign(othermatrix)</td>
    <td width="45%">best if othermatrix is a SparseDoubleMatrix2D</td>
  </tr>
  <tr> 
    <td width="20%">iteration</td>
    <td width="35%">forEachNonzero(function)</td>
    <td width="45%">often the preferred way for iteration and modification</td>
  </tr>
  <tr> 
    <td width="20%">&nbsp;</td>
    <td width="35%">&nbsp;</td>
    <td width="45%">&nbsp;</td>
  </tr>
</table>
</BODY>
</HTML>